import BlockUtil from "./BlockUtil.js"
import Playfield ,{ COLS as PLAYFIELD_COLS}from "./Playfield.js"
import Tetris, { TETRIS_TYPE ,COLS as TETRIS_COLS ,ROWS as TETRIS_ROWS} from "./Tetris.js"

//周期触发的定时器，一旦触发就让俄罗斯方块下落一行
let dropTimer = null
let dropTimerCnt = 0

const MAX_DROP_DELAY = 10
let dropDelay = MAX_DROP_DELAY

//存储音效的名称
//游戏结束
const defectSound = document.getElementById('defectSound')
//局内
const audio = document.getElementById('Sound')
//移动
const actionSound = document.getElementById('actionSound')
//消除，或者加分时
const eliSound = document.getElementById('eliSound')
//消除
const unbelievableSound = document.getElementById('unbelievableSound')



//创建一个vue应用程序的数据模型项
Vue.createApp({
    data(){
        return{
            //创建一个Playfield的实例作为他的值
            playfield: new Playfield(),
            //下一个即将落下的俄罗斯方块
            nextTetris: null,
            //当前正在移动的俄罗斯方块
            curTetris: null,
            clearableLines:[],
            //添加数据项
            isGameOver: false,
            score: 0,
            //标记游戏是否暂停
            isPaused: false,
            //是否开始
            isStart: false,

            //音乐是否正在播放
            musicPlaying: false, 

            //设置音效音量
            soundVolume: 0.5,


        }
    },
    computed:{
        playfieldBlocks(){
            //严谨一些，加个判定，如果没有当前正在移动的俄罗斯方块，就直接返回游戏区域的原始值
            if(!this.curTetris) return this.playfield.blocks
            //需要注意的是：不能直接拿游戏区域的数据进行操作
            //而应该先复制一个副本，使用deepcopy函数生成副本
            const pBlock = BlockUtil.deepCopy(this.playfield.blocks)
            //使用解构语法得到组成当前俄罗斯方块的小方块数据和位置信息
            const {blocks:tBlocks,position} = this.curTetris
            //再从位置信息里进一步解构，得到当前俄罗斯方块的行、列偏移值
            const {row:offsetRow,col:offsetCol} = position

            //使用定义的merge函数，实现游戏区域和当前俄罗斯方块数据的合并
            return BlockUtil.merge(pBlock,tBlocks,offsetRow,offsetCol)
        },
        //5000分提升一个等级，不需要存储等级值
        level(){
            return Math.floor(this.score / 5000) + 1
        }
    },
    methods:{
        //播放游戏整局的游戏音乐
        playMusic() {
            audio.volume = this.soundVolume
            if (audio) {
              audio.loop = true; // 设置循环播放
              audio.play().catch(error => {
                console.log("播放音频失败：", error);
              });
            }
        },
        // 设置音效音量，volume 应该是一个介于 0 到 1 之间的值
        setSoundVolume(volume) {
           
            this.soundVolume = volume;
        },
        //固化后应该重新生成一个俄罗斯方块
        createNextTetris(){
            //随机生成俄罗斯方块的类型，其中一种类型
            const type = Math.floor(Math.random() * TETRIS_TYPE.length)
            //随机旋转一个角度，取0-2之间的整数
            const rotate = Math.floor(Math.random() * 3)
            //构造一个新的俄罗斯方块
            this.nextTetris = new Tetris(type,rotate)
        },
        //负责把下一个俄罗斯方块丢到游戏区域
        dropTetris(){
            //将下一个俄罗斯方块赋值给当前方块
            this.curTetris = this.nextTetris
            //使用计算值
            this.curTetris.position = { 
                row: -TETRIS_ROWS,
                col: Math.floor((PLAYFIELD_COLS - TETRIS_COLS) / 2 )
            }

            //循环，快速的把当前俄罗斯方块从屏幕外落入到游戏区域内
            for(let i = 0;i < TETRIS_ROWS; i++){
                if(!this.moveTetris(1,0)) break;
            }

            //丢下俄罗斯方块后，再创建一块新的俄罗斯方块
            this.createNextTetris()
        },
        //先实现碰撞检测
        //同时检测移动和旋转两种操作时，俄罗斯方块是否碰撞
        //需要接收三个参数，移动时行、列方向的偏移量和旋转角度
        isCollided(offsetRow,offsetCol,rotate){
            //尽量不要把主程序里写具体代码
            //这里把碰撞检测的实现写到Playfield类里
            return this.playfield.isCollided(this.curTetris,offsetRow,offsetCol,rotate)

        },
        //再处理俄罗斯方块的操作
        //offsetRow,offsetCol分别是移动的偏移量
        //比如offsetRow是1时。表示向下移动一行
        //offsetCol是1时，表示向右移动一列，是-1时表示向左移动一列
        moveTetris(offsetRow,offsetCol){
            //如果没有发生碰撞，可以正常移动，则返回true
            if(!this.isCollided(offsetRow,offsetCol,0)){
                //调用当前俄罗斯方块对象的move（）方法进行移动
                this.curTetris.move(offsetRow,offsetCol)
                return true
            }else{
                //如果向下移动的过程中发生碰撞，就调用fixTetris()函数，完成固化
                if(offsetRow > 0) this.fixTetris()

                //否则返回false
                return false
            }
           

        },
        //旋转
        rotateTetris(rotate){
            if(!this.isCollided(0,0,rotate)){
                //同样，将旋转俄罗斯方块的rotate方法写进Tetris中
                this.curTetris.rotate(rotate)
            }
           
        },
        //负责积分累计
        addScore(score){
            this.score += score
            //积分增加后调整定时器的值，用最大周期数减去当前的等级数再加1
            dropDelay = Math.max(MAX_DROP_DELAY - this.level + 1,1)
        },
        //处理俄罗斯方块落到游戏区域最下方或落到已有方块上方时的情况
        //这两种情况下都应该把当前移动的俄罗斯方块“固化”
        fixTetris(){
            //每落地一个俄罗斯方块，+50
            this.addScore(50)
            //固化：将当前俄罗斯方块的数据真正合并到游戏区就可以了
            this.playfield.merge(this.curTetris)
            eliSound.play()

            //在快速下落的过程中，如果俄罗斯方块不能正常下落
            //游戏结束
            //增加一个判断，如果固化俄罗斯方块时，该方块还在游戏区域之外
            //执行游戏结束的逻辑
            if(this.curTetris.position.row < 0){
                //alert('Game Over!!')
                this.gameOver()
            }else{
                //固化俄罗斯方块后，丢下下一个俄罗斯方块前
                //先执行消除行的操作
                //clearLines()负责消除已经填满的行
                this.clearLines()
                //否则丢下一个新的俄罗斯方块
                this.dropTetris()
            }
        
        },
        //需要做三件事
        //1.计算可以被消除的行
        //2.闪烁
        //延迟后消除
        clearLines(){
            const { row: from } = this.curTetris.position
            //调用getClearableLines取得可以被消除的行，暂存到clearLines数组里
            //判定的起始行应该是俄罗斯方块所在行，结束行应该是起始行加俄罗斯方块的高度
            const clearLines 
                = this.clearableLines
                = this.playfield.getClearableLines(from,from + TETRIS_ROWS)

            //延时查看闪烁效果，再执行消除
            if(clearLines.length){
                //累计积分，消除n行得到的积分为（2^n）*100
                this.addScore((2 ** clearLines.length) * 100)
                setTimeout(() => {
                    //如果有可被消除的行就执行消除操作
                    this.playfield.clearLines(clearLines)
                    //完成后把数组清空
                    clearLines.splice(0)

                    unbelievableSound.play()
                   
                    if (eliSound) {
                        eliSound.play()
                      } else {
                        console.error('eliSound元素为null,无法播放音效。')
                    }
                    
                    //定时器，1s后再消除
                },1000)
              
            }
        },
        //启动定时器，定时器每0.05s触发一次，让当前俄罗斯方块下落一行
        startDropTimer(){
            if(!dropTimer){
                dropTimer = setInterval(() => {
                    //随着等级提升，下落的速度越快
                    if(dropTimerCnt++ > dropDelay){
                        this.moveTetris(1,0)
                        dropTimerCnt = 0
                    }
                   
                },50)
            }
        },
        //停止定时器
        stopDropTimer(){
            if(dropTimer){
                clearInterval(dropTimer)
                dropTimer = null
            }
        },
        gameOver(){
            //把定时器停止
            this.stopDropTimer()
            //游戏结束时为true
            this.isGameOver = true
            this.isStart = false

            // 游戏结束播放失败音效
            defectSound.play()
            
            //关闭局内音效
            if(this.musicPlaying){
                audio.pause()
                this.musicPlaying = false
            }
            

        },
        onKeydown(e){
            //控制台查看keydown事件触发时传递的事件对象
            //code值为按下的键，所以可以根据事件触发的code值来判断玩家按下的是哪一个键
            //console.log(e)

            if(!this.isStart || this.isPaused) return;
            switch(e.code){
                //按上键时，旋转俄罗斯方块
                //-1表示逆时针旋转90度
                case 'ArrowUp':
                    this.rotateTetris(-1)
                    actionSound.play()
                    break;
                //按下左、右、下方向键时，进行相应方向的移动
                case 'ArrowLeft':
                    this.moveTetris(0,-1)
                    actionSound.play()
                    break;
                case 'ArrowRight':
                    this.moveTetris(0,1)
                    actionSound.play()
                    break;
                case 'ArrowDown':
                    this.moveTetris(1,0)
                    actionSound.play()
                    break;

            }
        },
        //玩家点击start按钮时触发，游戏开始
        start(){


            this.isGameOver = false
            this.isStart = true
            this.score = 0
            this.dropDelay = MAX_DROP_DELAY
            this.curTetris = null
            //清空游戏区域
            this.playfield.clearAll()
            //丢下一个俄罗斯方块
            this.dropTetris()
            //启动控制方块自动下落的定时器
            this.startDropTimer()

            //播放音乐
             // 播放音乐（仅在开始时播放）
            if (!this.musicPlaying) {
                this.playMusic()
                this.musicPlaying = true // 标记音乐正在播放
            }
           
        },
        pause(){
            this.stopDropTimer()
            this.isPaused = true

            //暂停
            if(this.musicPlaying){
                audio.pause()
                this.musicPlaying = false
            }

        },
        resume(){
            this.startDropTimer()
            this.isPaused = false

            //继续播放音乐
            //如果音乐当前没有在播放
            if(!this.musicPlaying){
               // 如果音频对象存在且当前处于暂停状态
                if (audio && audio.paused) {
                    audio.play().catch(error => {
                      console.log("播放音频失败：", error)
                    });
                }
                this.musicPlaying = true
            }

            
        }
    },
    mounted(){
        //this.playfield.blocks[8] = [1,1,1,1,1,1,0,0,0,0]
        //使用键盘方向键控制俄罗斯方块移动的功能
        //要实现键盘控制，首先要监听键盘事件
        //在vue完成挂载后添加keydown事件的监听
        //回调onKeydown函数
        document.addEventListener('keydown',this.onKeydown)
        //this.startDropTimer()
        //vue完成挂载后，自动创建一个即将下落的俄罗斯方块
        this.createNextTetris()


    }
}).mount('#app')

//console.log(new Tetris(1).blocks)